from PIL import Image
import piexif
from fractions import Fraction


def convert_to_degrees(value):
    # Convert decimal coordinates to degrees, minutes, seconds
    degrees = int(value)
    minutes = int((value - degrees) * 60)
    seconds = (value - degrees - minutes / 60) * 3600
    return degrees, minutes, seconds


def to_rational(number):
    # Convert a number to a tuple (numerator, denominator)
    f = Fraction(number).limit_denominator()
    return f.numerator, f.denominator


def add_exif_location(image_path, output_path, lat, lon, alt):
    # Open an image file
    image = Image.open(image_path)

    # Prepare EXIF data
    exif_dict = {}
    if image.info.get('exif'):
        exif_dict = piexif.load(image.info['exif'])
    else:
        exif_dict = {
            '0th': {},
            'Exif': {},
            'GPS': {}
        }

    # Convert latitude and longitude to degrees, minutes, seconds
    lat_degrees, lat_minutes, lat_seconds = convert_to_degrees(abs(lat))
    lon_degrees, lon_minutes, lon_seconds = convert_to_degrees(abs(lon))

    # GPS data format
    exif_dict['GPS'][piexif.GPSIFD.GPSLatitudeRef] = 'N' if lat >= 0 else 'S'
    exif_dict['GPS'][piexif.GPSIFD.GPSLatitude] = [(to_rational(lat_degrees)), (to_rational(lat_minutes)),
                                                   (to_rational(lat_seconds))]
    exif_dict['GPS'][piexif.GPSIFD.GPSLongitudeRef] = 'E' if lon >= 0 else 'W'
    exif_dict['GPS'][piexif.GPSIFD.GPSLongitude] = [(to_rational(lon_degrees)), (to_rational(lon_minutes)),
                                                    (to_rational(lon_seconds))]

    # Add altitude
    exif_dict['GPS'][piexif.GPSIFD.GPSAltitudeRef] = 0 if alt >= 0 else 1  # 0 = Above sea level, 1 = Below sea level
    exif_dict['GPS'][piexif.GPSIFD.GPSAltitude] = to_rational(abs(alt))

    # Convert dict to bytes
    exif_bytes = piexif.dump(exif_dict)

    # Save the image with the new EXIF data
    image.save(output_path, "jpeg", exif=exif_bytes)


# Example usage
image_path = 'input.jpg'
output_path = 'output.jpg'
latitude = 30.8
longitude = 120.8060
altitude = 10.0  # Height in meters
add_exif_location(image_path, output_path, latitude, longitude, altitude)
